/**
 * 
 */
package com.wgo.precise.client.common.session;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

import com.wgo.bpot.common.removeme.Persistent;
import com.wgo.bpot.common.transport.exception.RematoException;
import com.wgo.precise.service.PreciseService;

/**
 * @author peide3
 *
 */
public class PreciseServiceClientImpl implements PreciseService {

	private URL remoteUrl;
	private static Method importFromXmlMethod;
	private static Method exportToXmlMethod;
	private static Method getPdfMethod;
	
	static {
		try {
			importFromXmlMethod = PreciseService.class.getMethod("importFromXml", byte[].class);
			exportToXmlMethod = PreciseService.class.getMethod("exportToXml");
			getPdfMethod = PreciseService.class.getMethod("getPdf", Class.class, Serializable.class);
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * @param remoteUrl
	 * @param servletName
	 */
	public PreciseServiceClientImpl(URL remoteUrl, String servletName) {
		try {
			this.remoteUrl = new URL (remoteUrl.toExternalForm() + servletName) ;
		} catch (MalformedURLException e) {
			throw new RematoException("Invalid URL: " + remoteUrl + servletName, e);
		}
	}

	/**
	 * @see com.wgo.precise.service.PreciseService#importFromXML(java.io.File)
	 */
	public boolean importFromXml(byte[] preciseXmlFile) {
		return this.<Boolean>prosessRequest(importFromXmlMethod, preciseXmlFile);
	}

	/**
	 * @see com.wgo.precise.service.PreciseService#exportFromXML()
	 */
	public byte[] exportToXml() {
		return this.<byte[]>prosessRequest(exportToXmlMethod);
	}

	/**
	 * @see com.wgo.precise.service.PreciseService#getPdf(com.wgo.bpot.common.removeme.Persistent)
	 */
	public byte[] getPdf(Class<? extends Persistent> conceptType, Serializable identifier) {
		return this.<byte[]>prosessRequest(getPdfMethod, conceptType, identifier);
	}
	
	@SuppressWarnings("unchecked")
	private <T> T prosessRequest(Method method, Object... args) {
		Object returnValue = null;
		try {
 			URLConnection con = remoteUrl.openConnection();
			con.setDoOutput(true);
			con.setDoInput(true);
			con.setUseCaches(false);
			con.setRequestProperty("Content-Type", "application/octet-stream");
 
			ObjectOutputStream request = new ObjectOutputStream(new BufferedOutputStream(con.getOutputStream()));
			request.writeObject(method.getName());
			request.writeObject(method.getParameterTypes());
			request.writeObject(args);

			request.flush();
			request.close();
 
			ObjectInputStream response = new ObjectInputStream(new BufferedInputStream(con
					.getInputStream()));
			
			returnValue = response.readObject();
			if (returnValue instanceof Throwable) {
				throw ((Throwable)returnValue);
			}
 
		} catch (Throwable e) {
			throw new RematoException("Call to precise service failed.", e);
		}
		return (T)returnValue;
		
	}

}
